function FreeboardModel(datasourcePlugins, widgetPlugins, freeboardUI)
{
    var self = this;

    var SERIALIZATION_VERSION = 1;

    this.version = 0;
    this.isEditing = ko.observable(false);
    this.allow_edit = ko.observable(false);
    this.allow_edit.subscribe(function(newValue)
    {
        if(newValue)
        {
            $("#main-header").show();
        }
        else
        {
            $("#main-header").hide();
        }
    });

    this.header_image = ko.observable();
    this.plugins = ko.observableArray();
    this.datasources = ko.observableArray();
    this.panes = ko.observableArray();
    this.datasourceData = {};
    this.processDatasourceUpdate = function(datasourceModel, newData)
    {
        var datasourceName = datasourceModel.name();

        self.datasourceData[datasourceName] = newData;

        _.each(self.panes(), function(pane)
        {
            _.each(pane.widgets(), function(widget)
            {
                widget.processDatasourceUpdate(datasourceName);
            });
        });
    }

    this._datasourceTypes = ko.observable();
    this.datasourceTypes = ko.computed({
        read: function()
        {
            self._datasourceTypes();

            var returnTypes = [];

            _.each(datasourcePlugins, function(datasourcePluginType)
            {
                var typeName = datasourcePluginType.type_name;
                var displayName = typeName;

                if(!_.isUndefined(datasourcePluginType.display_name))
                {
                    displayName = datasourcePluginType.display_name;
                }

                returnTypes.push({
                    name        : typeName,
                    display_name: displayName
                });
            });

            return returnTypes;
        }
    });

    this._widgetTypes = ko.observable();
    this.widgetTypes = ko.computed({
        read: function()
        {
            self._widgetTypes();

            var returnTypes = [];

            _.each(widgetPlugins, function(widgetPluginType)
            {
                var typeName = widgetPluginType.type_name;
                var displayName = typeName;

                if(!_.isUndefined(widgetPluginType.display_name))
                {
                    displayName = widgetPluginType.display_name;
                }

                returnTypes.push({
                    name        : typeName,
                    display_name: displayName
                });
            });

            return returnTypes;
        }
    });

    this.addPluginSource = function(pluginSource)
    {
        if(pluginSource && self.plugins.indexOf(pluginSource) == -1)
        {
            self.plugins.push(pluginSource);
        }
    }

    this.serialize = function()
    {
        var panes = [];

        _.each(self.panes(), function(pane)
        {
            panes.push(pane.serialize());
        });

        var datasources = [];

        _.each(self.datasources(), function(datasource)
        {
            datasources.push(datasource.serialize());
        });

        return {
            version     : SERIALIZATION_VERSION,
            header_image: self.header_image(),
            allow_edit  : self.allow_edit(),
            plugins     : self.plugins(),
            panes       : panes,
            datasources : datasources,
            columns     : freeboardUI.getUserColumns()
        };
    }

    this.deserialize = function(object, finishedCallback)
    {
        self.clearDashboard();

        function finishLoad()
        {
            freeboardUI.setUserColumns(object.columns);

            if(!_.isUndefined(object.allow_edit))
            {
                self.allow_edit(object.allow_edit);
            }
            else
            {
                self.allow_edit(true);
            }
            self.version = object.version || 0;
            self.header_image(object.header_image);

            _.each(object.datasources, function(datasourceConfig)
            {
                var datasource = new DatasourceModel(self, datasourcePlugins);
                datasource.deserialize(datasourceConfig);
                self.addDatasource(datasource);
            });

            var sortedPanes = _.sortBy(object.panes, function(pane){
                return freeboardUI.getPositionForScreenSize(pane).row;
            });

            _.each(sortedPanes, function(paneConfig)
            {
                var pane = new PaneModel(self, widgetPlugins);
                pane.deserialize(paneConfig);
                self.panes.push(pane);
            });

            if(self.allow_edit() && self.panes().length == 0)
            {
                self.setEditing(true);
            }

            if(_.isFunction(finishedCallback))
            {
                finishedCallback();
            }

            freeboardUI.processResize(true);
        }

        // This could have been self.plugins(object.plugins), but for some weird reason head.js was causing a function to be added to the list of plugins.
        _.each(object.plugins, function(plugin)
        {
            self.addPluginSource(plugin);
        });

        // Load any plugins referenced in this definition
        if(_.isArray(object.plugins) && object.plugins.length > 0)
        {
            head.js(object.plugins, function()
            {
                finishLoad();
            });
        }
        else
        {
            finishLoad();
        }
    }

    this.clearDashboard = function()
    {
        freeboardUI.removeAllPanes();

        _.each(self.datasources(), function(datasource)
        {
            datasource.dispose();
        });

        _.each(self.panes(), function(pane)
        {
            pane.dispose();
        });

        self.plugins.removeAll();
        self.datasources.removeAll();
        self.panes.removeAll();
    }

    this.loadDashboard = function(dashboardData, callback)
    {
        freeboardUI.showLoadingIndicator(true);
        self.deserialize(dashboardData, function()
        {
            freeboardUI.showLoadingIndicator(false);

            if(_.isFunction(callback))
            {
                callback();
            }

            freeboard.emit("dashboard_loaded");
        });
    }

    this.loadDashboardFromLocalFile = function()
    {
        // Check for the various File API support.
        if(window.File && window.FileReader && window.FileList && window.Blob)
        {
            var input = document.createElement('input');
            input.type = "file";
            $(input).on("change", function(event)
            {
                var files = event.target.files;
                if(files && files.length > 0)
                {
                    var file = files[0];
                    var reader = new FileReader();
                    reader.addEventListener("load", function(fileReaderEvent)
                    {
                        var textFile = fileReaderEvent.target;
                        var jsonObject = JSON.parse(textFile.result);
                        window.open('_blank');
                        self.loadDashboard(jsonObject);
                        self.setEditing(false);
                    });
                    reader.readAsText(file);
                }
            });
            $(input).trigger("click");
        }
        else
        {
            alert('Unable to load a file in this browser.');
        }
    }
    /*
    this.saveDashboardClicked = function(){
        var target = $(event.currentTarget);
        var siblingsShown = target.data('siblings-shown') || false;
        if(!siblingsShown){
            $(event.currentTarget).siblings('label').fadeIn('slow');
        }else{
            $(event.currentTarget).siblings('label').fadeOut('slow');
        }
        target.data('siblings-shown', !siblingsShown);
    }
	*/
    //此处应该是传到后台数据库把...我这里直接将新的dashboard传到了本地
    this.saveDashboard = function(_thisref, event) {
		var dashboardDate= JSON.stringify(self.serialize());
        console.log(dashboardDate);
        $.ajax({
            //async: false,
            url: "http://localhost:8080/Demo/use/putDate.do",
            //dataType: "json",
            type: "POST",
            contentType : "application/json",
			data:dashboardDate,
            success: function (data) {
                //window.location.href="http://localhost:63342/freeboard/index-dev2.html?_ijt=kvsi9ffdu6p5ikvod8fi1t1c3g";
            },
            error: function (xhr, status, error) {
            }
        });
    };

    this.addDatasource = function(datasource)
    {
        self.datasources.push(datasource);
    }

    this.deleteDatasource = function(datasource)
    {
        delete self.datasourceData[datasource.name()];
        datasource.dispose();
        self.datasources.remove(datasource);
    }

    this.createPane = function()
    {
        var newPane = new PaneModel(self, widgetPlugins);
        self.addPane(newPane);
    }

    this.addGridColumnLeft = function()
    {
        freeboardUI.addGridColumnLeft();
    }

    this.addGridColumnRight = function()
    {
        freeboardUI.addGridColumnRight();
    }

    this.subGridColumnLeft = function()
    {
        freeboardUI.subGridColumnLeft();
    }

    this.subGridColumnRight = function()
    {
        freeboardUI.subGridColumnRight();
    }

    this.addPane = function(pane)
    {
        self.panes.push(pane);
    }

    this.deletePane = function(pane)
    {
        pane.dispose();
        self.panes.remove(pane);
    }

    this.deleteWidget = function(widget)
    {
        ko.utils.arrayForEach(self.panes(), function(pane)
        {
            pane.widgets.remove(widget);
        });

        widget.dispose();
    }

    this.setEditing = function(editing, animate)
    {
        // Don't allow editing if it's not allowed
        if(!self.allow_edit() && editing)
        {
            return;
        }
        self.isEditing(editing);
        if(_.isUndefined(animate))
        {
            animate = true;
        }
        var animateLength = (animate) ? 250 : 0;
        var barHeight = $("#admin-bar").outerHeight();

        if(!editing)
        {
            $("#toggle-header-icon").addClass("icon-wrench").removeClass("icon-chevron-up");
            $(".gridster .gs_w").css({cursor: "default"});
            $("#main-header").animate({"top": "-" + barHeight + "px"}, animateLength);
            $("#board-content").animate({"top": "20"}, animateLength);
            $("#main-header").data().shown = false;
            $(".sub-section").unbind();
            freeboardUI.disableGrid();
        }
        else
        {
            $("#toggle-header-icon").addClass("icon-chevron-up").removeClass("icon-wrench");
            $(".gridster .gs_w").css({cursor: "pointer"});
            $("#main-header").animate({"top": "0px"}, animateLength);
            $("#board-content").animate({"top": (barHeight + 20) + "px"}, animateLength);
            $("#main-header").data().shown = true;
            freeboardUI.attachWidgetEditIcons($(".sub-section"));
            freeboardUI.enableGrid();
        }

        freeboardUI.showPaneEditIcons(editing, animate);
    }

    this.toggleEditing = function()
    {
        var editing = !self.isEditing();
        self.setEditing(editing);
    }
}
